package app

import (
	"daqctl/internal/config"
	"encoding/json"
	"strings"

	"fmt"

	logr "github.com/sirupsen/logrus"
)

type App struct {
	Name    string            `json:"name"`
	Desc    string            `json:"desc"`
	Type    string            `json:"type"`
	State   string            `json:"state"`
	Metrics map[string]string `json:"metrics"`
}

type ROSMetrics struct {
	App
	ClearedL1idCount string `json:"cleared_l1id_count"`
}

const (
	AppType     string = "type"
	ROSType     string = "ros"
	BuilderType string = "eb"
	PSType      string = "ps"
	ESType      string = "es"
	DFMType     string = "dfm"
	AllType     string = "all"

	ROSTypeDesc       string = "Read Out"
	BuilderTypeDesc   string = "Builder"
	ProcessorTypeDesc string = "Porcessor"
	ESTypeDesc        string = "Event Storage"
	DFMTypeDesc       string = "DataFlow Manager"

	ROSPrefix     string = "ros"
	BuilderPrefix string = "builder"
	PSPrefix      string = "ps"
	ESPrefix      string = "es"
	DFMPrefix     string = "dfm"

	//df.apptype.appid.metrics
	ROSMetricsPattern     string = "df.ros:%s.%s"
	BuilderMetricsPattern string = "df.builder:%s.%s"
	PSMetricsPattern      string = "df.processor:%s.%s"
	ESMetricsPattern      string = "df.es:%s.%s"
	DFMMetricsPattern     string = "df.dfm:%s.%s"
)

func Apps() []App {
	var apps []App

	apps = append(apps, ROSApps()...)
	apps = append(apps, BuilderApps()...)
	apps = append(apps, PSApps()...)
	apps = append(apps, ESApps()...)
	apps = append(apps, DFMApps()...)

	return apps
}

// ROSApps 初始化ros
func ROSApps() []App {
	apps := []App{}

	for i := 0; i < config.DaqCtlConfig.RosNumber; i++ {
		apps = append(apps, App{
			Name:    fmt.Sprintf("%s-%d", ROSPrefix, i),
			Desc:    ROSTypeDesc,
			Type:    ROSType,
			Metrics: map[string]string{},
		})
	}

	return apps
}

// BuilderApps 初始化builder
func BuilderApps() []App {
	apps := []App{}

	for i := 0; i < config.DaqCtlConfig.BuilderNumber; i++ {
		apps = append(apps, App{
			Name:    fmt.Sprintf("%s-%d", BuilderPrefix, i),
			Desc:    BuilderTypeDesc,
			Type:    BuilderType,
			Metrics: map[string]string{},
		})
	}

	return apps
}

// PSApps 初始化ps
func PSApps() []App {
	apps := []App{}

	for i := 0; i < config.DaqCtlConfig.PsNumber; i++ {
		apps = append(apps, App{
			Name:    fmt.Sprintf("%s-%d", PSPrefix, i),
			Type:    PSType,
			Desc:    ProcessorTypeDesc,
			Metrics: map[string]string{},
		})
	}

	return apps
}

// ESApps 初始化es
func ESApps() []App {
	apps := []App{}

	for i := 0; i < config.DaqCtlConfig.EsNumber; i++ {
		apps = append(apps, App{
			Name:    fmt.Sprintf("%s-%d", ESPrefix, i),
			Type:    ESType,
			Desc:    ESTypeDesc,
			Metrics: map[string]string{},
		})
	}

	return apps
}

// DFMApps 初始化dfm
func DFMApps() []App {
	apps := []App{}

	for i := 0; i < config.DaqCtlConfig.DfmNumber; i++ {
		apps = append(apps, App{
			Name:    fmt.Sprintf("%s-%d", DFMPrefix, i),
			Type:    DFMType,
			Desc:    DFMTypeDesc,
			Metrics: map[string]string{},
		})
	}

	return apps
}

// GetROSMetricNames 获取ROS的metrics name
func GetROSMetricNames() []string {
	// metrics
	metrcis := []string{"cleared_l1id_count", "sentfrag_l1id_count", "cleared_l1id", "sentfrag_l1id", "ros_datarate", "ro_frags"}

	return metrcis
}

func GetBuilderMetricNames() []string {
	// metrics
	metrcis := []string{"input_ros_count", "input_ros_volume", "built_timed_count", "builder_datarate", "output_timed_count",
		"output_timed_volume", "assigned_l1id.value", "cleared_l1id.value", "assigned_l1id_count", "cleared_l1id_count"}

	return metrcis
}

func GetProcessorMetricNames() []string {
	// metrics
	metrcis := []string{"input_timed_count", "input_timed_volume", "triggered_event_count", "output_event_count", "output_event_volume",
		"input_timed_l1id.value", "output_event_l1id.value", "buffered_wait_for_HOEC_count.value", "type_queue_count.value", "send_queue_count.value",
		"buffered_timed_fragment_count.value"}

	return metrcis
}

func GetEventStorageMetricNames() []string {
	// metrics
	metrcis := []string{"input_event_l1id", "output_event_l1id", "input_event_count", "input_event_volume", "saved_event_count", "saved_event_volume"}

	return metrcis
}

func GetDFMMetricNames() []string {
	// metrics
	metrcis := []string{"ros_l1id", "ready_build_l1id", "built_l1id", "cleared_l1id", "ros_l1id.current_value", "ready_build_l1id.current_value",
		"cleared_l1id.current_value", "es.acked_l1id.current_value", "ps.assigned_l1id.current_value", "ps.finished_l1id.current_value",
		"ps.processing", "ps.processed", "ps.sending", "ps.sent_but_not_erased"}

	return metrcis
}

//MatchAppType 匹配字符串前两个字符，转换成app type
func MatchAppType(str string) string {
	if strings.HasPrefix(str, "ro") {
		return ROSType
	} else if strings.HasPrefix(str, "bu") || strings.HasPrefix(str, "eb") {
		return BuilderType
	} else if strings.HasPrefix(str, "ps") {
		return PSType
	} else if strings.HasPrefix(str, "es") || strings.HasPrefix(str, "ev") {
		return ESType
	} else if strings.HasPrefix(str, "df") {
		return DFMType
	}
	return AllType
}

//MatchAppTypeDesc 匹配字符串前两个字符，转换成app type desc
func MatchAppTypeDesc(str string) string {
	if strings.HasPrefix(str, "ro") {
		return ROSTypeDesc
	} else if strings.HasPrefix(str, "bu") || strings.HasPrefix(str, "eb") {
		return BuilderTypeDesc
	} else if strings.HasPrefix(str, "ps") {
		return ProcessorTypeDesc
	} else if strings.HasPrefix(str, "es") || strings.HasPrefix(str, "ev") {
		return ESTypeDesc
	} else if strings.HasPrefix(str, "df") {
		return DFMTypeDesc
	}
	return ""
}

func Apps2Maps(objs []App) []map[string]string {
	maps := []map[string]string{}
	for _, obj := range objs {
		metrics, err := json.Marshal(obj.Metrics)
		if err != nil {
			logr.Error(err)
			return maps
		}
		line := map[string]string{
			"Name":    obj.Name,
			"Type":    obj.Type,
			"Desc":    obj.Desc,
			"State":   obj.State,
			"Metrics": string(metrics),
		}
		maps = append(maps, line)
	}
	return maps
}
